Author: Jorge Maldonado Ventura
Category: Bash
Date: 2018-02-08 19:37
Lang: es
Modified: 2020-10-21
Slug: apagar-ordenador-automáticamente-tras-finalizar-proceso
Tags: ||, apagar, do, done, GNU/Linux, pgrep, PID, proceso, operador de lista, ps, shutdown, sleep, test, truco, wget, while
Title: Apagar ordenador automáticamente tras finalizar proceso

A veces queremos apagar el ordenador, pero hay una tarea en curso (p.
ej., una descarga, actualización...). Podemos esperar a que termine para
apagar el ordenador manualmente o podemos decirle al ordenador que se
apague cuando se complete el proceso. En este artículo os muestro cómo
realizar la solución automatizada.

<!-- more -->

Este artículo puede resultar peligroso si copias las instrucciones a
mano y cometes un error, pues se puede apagar el ordenador. Recomiendo
leer y comprender las instrucciones aquí mostradas antes de copiarlas
literalmente.

Supongamos que hemos realizado una descarga con el programa
[wget](https://www.gnu.org/software/wget) y sabemos que la descarga se
completará en una hora aproximadamente. Podríamos programar el apagado
del ordenador entonces para dentro de una hora con la instrucción
`shutdown +60`, aunque siempre es recomendable dejar algo más de tiempo.

Este enfoque tiene el grave inconveniente de que, si por alguna razón la
tarea se retrasa, es posible que la descarga no se complete. Para
solucionar este problema, vamos a hacer que se apague el ordenador
cuando la tarea se haya completado.

Cada tarea tiene asignado un identificador de proceso (abreviado <abbr
title="Process ID">PID</abbr>). Para obtener el número de proceso de un
programa podemos utilizar la instrucción pgrep, pasándole como argumento
el nombre del programa.

<pre><samp>$ pgrep wget
3204</samp></pre>

El programa devuelve un estado de salida de cero (éxito) y muestra el
resultado de la ejecución (<samp>3204</samp>). Si no hay ningún proceso
que contiene la cadena `wget` en ejecución, pgrep devuelve un estado de
salida de 1.

A continuación, vamos a escribir un bucle con `while` para que compruebe
si pgrep devuelve 0 como estado de salida cada cinco segundos. Si no lo
hace, apagamos el ordenador. En el código, abajo, hacemos uso del
operador de lista `||`. La instrucción que haya antes de `||` se
ejecutará siempre; la que haya después solo se ejecutará si la anterior
falla. Como pgrep muestra la salida de la instrucción por pantalla y no
me interesa verla cada 5 segundos, la redirijo a `/dev/null` con `>`
(esto hace que se deseche).

    :::bash
    while true; do
        pgrep wget > /dev/null || shutdown now
        sleep 5
    done

Si estas instrucciones se van a ejecutar muchas veces, es recomendable
programar un guion que nos permita pasarle un parámetro para indicar el
programa que queremos controlar.

El método anterior supone problemas para casos en los que pgrep devuelve
más de un resultado, pero se puede solucionar controlando solo el
identificador del proceso que nos interesa y comprobando que este aún
se esté ejecutando. Vamos a imaginar que solo queremos detener el
proceso con el identificador número 1091 para los siguientes ejemplos.

Podemos comprobar si un proceso sigue en ejecución analizando la salida
del programa ps con la opción `-q`, y el número de proceso como su
argumento.

    :::bash
    while true; do
        ps -q 1091 > /dev/null || shutdown now
        sleep 5
    done

En GNU/Linux, los procesos crean un directorio, cuyo nombre es el
identificador del proceso, dentro del directorio `/proc/`. Es decir, el
proceso con el identificador 1091 tiene asignado el fichero
`/proc/1019`. Una vez que finalice el proceso desaparecerá dicho
fichero.

    :::bash
    while true; do
        test -d /proc/1091 || shutdown now
        sleep 5
    done

Con cualquiera de los anteriores métodos es sencillo programar el
apagado del ordenador tras completar una tarea. Aunque no es muy
probable, ten en cuenta que cualquier otro nuevo proceso podría obtener
el identificador de proceso de la instrucción que estás controlando
&mdash;por ejemplo, esto se puede hacer usando la instrucción integrada
de Bash exec&mdash;.
